package org.smartboot.flow.springboot.extension;

import org.smartboot.flow.manager.EngineInitializer;
import org.smartboot.flow.manager.reload.Reloader;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

/**
 * smart flow EngineInitializer auto config
 *
 * @author huqiang
 * @since 2022/12/15 16:32
 */
@Configuration
@ConfigurationProperties(prefix = "smart.flow.initialize")
@ConditionalOnProperty(name = "smart.flow.initialize.engines")
@AutoConfigureAfter(FlowReloadConfiguration.class)
public class FlowInitializerConfiguration implements BeanPostProcessor, BeanFactoryAware {

    /**
     * Initializer engines, multiple engine name split with ,
     */
    private String engines;

    /**
     * Ensure EngineInitializer#start execute in high order.
     */
    private volatile boolean processed;
    private BeanFactory beanFactory;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // Fire EngineInitializer#start
        this.process();
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    private void process() {
        if (processed) {
            return;
        }

        processed = true;

        try {
            beanFactory.getBean("springboot-engine-initializer");
        } catch (Exception ignored) {
            try {
                beanFactory.getBean(EngineInitializer.class);
            } catch (Exception ignore) {

            }
        }
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Bean(value = "springboot-engine-initializer", initMethod = "start")
    @ConditionalOnBean(Reloader.class)
    @ConditionalOnMissingBean(EngineInitializer.class)
    public EngineInitializer getInitializer(Reloader reloader) {
        EngineInitializer initializer = new EngineInitializer();
        initializer.setReloader(reloader);
        initializer.setEngines(Arrays.asList(engines.split(",")));
        return initializer;
    }


    public void setEngines(String engines) {
        this.engines = engines;
    }
}
